﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;

namespace Emico.Linq.Criterion
{
    [Serializable]
    public class NotInExpression<T, TValue> : ContainExpression<T, TValue>
        where T : class
    {
        public NotInExpression(string propertyName, IEnumerable<TValue> values)
            : base(propertyName, values)
        {
        }

        public NotInExpression(Expression<Func<T, TValue>> selector, IEnumerable<TValue> values)
            : this(new PropertyPathVisitor().GetPropertyPath(selector), values)
        {
        }

        protected NotInExpression(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        #region Implement Abstract Method

        public override Expression ToLinqExpression(Criteria<T> criteria, ParameterExpression parameter)
        {
            Expression selector = ExpressionHelper.CrateNestExpressionProperty<T>(this.PropertyName, parameter);
            var equals = this.Values.Select(value => (Expression)Expression.NotEqual(selector, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.And(accumulate, equal));
            return body;
        }

        #endregion
    }
}
